<?php

namespace nabu\controllers\adminController;

defined('NABU') || exit;

require_once 'libs/csrf.php';
require_once 'libs/validations.php';
require_once 'models/adminModel.php';
require_once 'libs/utils.php';

use nabu\libs\csrf\csrf,
    nabu\libs\validations\validations,
    nabu\models\adminModel\adminModel,
    nabu\libs\utils\utils;

// Administra cuentas de usuario y modera las publicaciones de artículos.
class adminController {
  private static function default_route() {
    $GLOBALS['messages'] -> redirect(NABU_ROUTES['admin']);
  }

  private static function home() {
    $GLOBALS['messages'] -> redirect(NABU_ROUTES['home']);
  }

  // Renderiza la página web principal del panel de administración,
  // edición, autorización y eliminación de artículos.
  public static function admin() {
    if (!utils::is_admin())
      self::home();

    if (empty($_GET['page'])) {
      $head_title = 'Administración';
      $messages   = $GLOBALS['messages'] -> messages();

      $adminModel = new adminModel();

      // Lista todos los artículos enviados.
      $articles = $adminModel -> sent_articles();

      // Formatea los datos de los artículos durante la marcha.
      foreach ($articles as &$article) {
        $article['title'] = utils::str_escape($article['title']);
        $article['author'] = utils::str_escape($article['author']);
      }

      unset($adminModel, $article);

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/admin_navbar.php';
      require_once 'views/admin/admin.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      if (empty($_GET['slug']))
        self::default_route();

      switch ($_GET['page']) {
        case 'edit':
          self::edit_article();
          break;
        case 'authorize':
          self::authorize_article();
          break;
        case 'delete':
          self::delete_article();
          break;
        default:
          self::default_route();
      }
    }
  }

  // Renderiza la página web de edición de artículos.
  private static function edit_article() {
    if (empty($_POST['edit_article'])) {
      $adminModel = new adminModel();

      // Busca los datos de un artículo dado su URL.
      $article = $adminModel -> find_article($_GET['slug']);

      unset($adminModel);

      if ($article === false)
        self::default_route();

      $head_title = 'Editar artículo';
      $token      = csrf::generate_token();
      $messages   = $GLOBALS['messages'] -> messages();

      // Muestra la portada de un artículo si fue cargado anteriormente.
      if (!empty($article['cover']))
        $article['cover'] = NABU_DIRECTORY['covers'] . '/' . $article['cover'];

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/admin_navbar.php';
      require_once 'views/admin/edit_article.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      csrf::validate_token($_POST['csrf']);

      self::update_article($_POST);
    }
  }

  // Valida los campos del formulario de edición de artículos y
  // actualiza los datos de un artículo.
  private static function update_article($form) {
    $adminModel = new adminModel();

    $article = $adminModel -> find_article($_GET['slug']);

    if ($article === false)
      self::default_route();

    $form = array_merge($form, $_FILES);

    $validations = new validations(NABU_ROUTES['edit_article'] . '&slug=' . $article['slug']);

    // Valida los campos del formulario de edición de artículos.
    $data = $validations -> validate_form($form, array(
      array('cover',    'type' => 'image', 'max'      => NABU_DEFAULT['image_size']),
      array('title',    'exist' => true,   'max'      => 246, 'trim_all' => true),
      array('synopsis', 'exist' => true,   'trim_all' => true),
      array('content',  'exist' => true,   'max'      => NABU_DEFAULT['article_size'], 'trim' => true)
    ));

    global $messages;

    $update = array();

    // Valida si hay cambios en la portada del artículo.
    if (!empty($data['cover'])) {
      $extension = explode('/', $data['cover']['type'])[1];

      if ($extension == 'svg+xml')
        $extension = 'svg';

      // Valida si el nombre de la portada es único.
      do
        $filename = bin2hex(random_bytes(32)) . '.' . $extension;
      while ($adminModel -> article_id('cover', $filename));

      $destination = NABU_DIRECTORY['storage_covers'] . '/' . $filename;

      // Guarda la nueva portada en la capeta de almacenamiento de portadas de artículos.
      if (move_uploaded_file($data['cover']['tmp_name'], $destination)) {
        $update['cover'] = $filename;

        // Remueve la portada anterior.
        if (!empty($article['cover'])) {
          $cover = NABU_DIRECTORY['storage_covers'] . '/' . $article['cover'];

          if (file_exists($cover))
            unlink($cover);

          unset($cover);
        }

        $messages -> add_message('La portada del artículo se ha actualizado correctamente');
      }
      else
        $messages -> add_message('¡Lo sentimos mucho! &#x1F61E;, por el momento no podemos actualizar la portada del artículo');

      unset($extension, $filename, $destination);
    }

    // Valida si hay cambios en el título del artículo.
    if ($data['title'] != $article['title']) {
      $slug = utils::url_slug($data['title']);

      // Valida la longitud de la URL.
      $validations -> validate_form(array('slug' => $slug), array(
        array('slug', 'exist' => true)
      ));

      // Valida si la URL es única.
      if ($adminModel -> article_id('slug', $slug))
        $messages -> add_message('Por favor define un título diferente o espera máximo un día para actualizar el artículo');
      else {
        $update['title'] = $data['title'];
        $update['slug']  = $slug;

        $messages -> add_message('El título del artículo se ha actualizado correctamente');
      }

      unset($slug);
    }

    // Valida si hay cambios en el resumen del artículo.
    if ($data['synopsis'] != $article['synopsis']) {
      $update['synopsis'] = $data['synopsis'];

      $messages -> add_message('El resumen del artículo se ha actualizado correctamente');
    }

    // Valida si hay cambios en el contenido del artículo.
    if ($data['content'] != $article['content']) {
      $update['content'] = $data['content'];

      $messages -> add_message('El contenido del artículo se ha actualizado correctamente');
    }

    // Actualiza los datos del artículo en la base de datos.
    if (!empty($update)) {
      $adminModel -> update_article($article['id'], $update);

      if (!empty($update['slug']))
        $article['slug'] = $update['slug'];
    }

    $messages -> redirect(NABU_ROUTES['edit_article'] . '&slug=' . $article['slug']);
  }

  // Autoriza la publicación de un artículo.
  private static function authorize_article() {
    global $messages;

    $view = NABU_ROUTES['authorize_article'] . '&slug=' . $_GET['slug'];

    if (empty($_POST['confirm_password_submit'])) {
      $head_title = 'Autorizar artículo';
      $token      = csrf::generate_token();
      $messages   = $messages -> messages();
      $subtitle   = 'Escribe tu contraseña para autorizar el artículo';

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/admin_navbar.php';
      require_once 'views/pages/confirm_password.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      csrf::validate_token($_POST['csrf']);

      $validations = new validations($view);

      // Valida los campos del formulario de confirmación de contraseña.
      $data = $validations -> validate_form($_POST, array(
        array('password', 'exist' => true, 'trim' => true, 'min' => 6, 'equal' => array(true, $_POST['password_confirm']), 'not_spaces' => true)
      ));

      $adminModel = new adminModel();

      // Obtiene el hash de la contraseña del usuario.
      $hash = $adminModel -> find_password($_SESSION['user']['id']);

      if ($hash === false)
        $messages -> redirect(NABU_ROUTES['logout']);

      // Valida la contraseña del usuario para completar la operación.
      if (!password_verify($data['password'], $hash)) {
        $messages -> add_message('La contraseña es incorrecta');
        $messages -> redirect($view);
      }

      // Obtiene el id del artículo.
      $id = $adminModel -> article_id('slug', $_GET['slug']);

      if ($id === false)
        self::default_route();

      // Autoriza la publicación del artículo.
      $adminModel -> post_article($id);

      $messages -> add_message('Artículo publicado con éxito');

      self::default_route();
    }
  }

  // Elimina un artículo.
  private static function delete_article() {
    global $messages;

    $view = NABU_ROUTES['delete_article'] . '&slug=' . $_GET['slug'];

    if (empty($_POST['confirm_password_submit'])) {
      $head_title = 'Eliminar artículo';
      $token      = csrf::generate_token();
      $messages   = $messages -> messages();
      $subtitle   = 'Escribe tu contraseña para eliminar el artículo';

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/admin_navbar.php';
      require_once 'views/pages/confirm_password.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      csrf::validate_token($_POST['csrf']);

      $validations = new validations($view);

      // Valida los campos del formulario de confirmación de contraseña.
      $data = $validations -> validate_form($_POST, array(
        array('password', 'exist' => true, 'trim' => true, 'min' => 6, 'equal' => array(true, $_POST['password_confirm']), 'not_spaces' => true)
      ));

      $adminModel = new adminModel();

      // Obtiene el hash de la contraseña del usuario.
      $hash = $adminModel -> find_password($_SESSION['user']['id']);

      if ($hash === false)
        $messages -> redirect(NABU_ROUTES['logout']);

      // Valida la contraseña del usuario para completar la operación.
      if (!password_verify($data['password'], $hash)) {
        $messages -> add_message('La contraseña es incorrecta');
        $messages -> redirect($view);
      }

      // Obtiene el id del artículo.
      $id = $adminModel -> article_id('slug', $_GET['slug']);

      if ($id === false)
        self::default_route();

      // Elimina el artículo en la base de datos.
      $adminModel -> delete_article($id);

      $messages -> add_message('El artículo fue eliminado');

      self::default_route();
    }
  }
}
